home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 42 / Amiga Format AFCD42 (Issue 126, Aug 1999).iso / -serious- / comms / other / slrn / slrn_src / src / uudecode.c < prev    next >
C/C++ Source or Header  |  1999-05-14  |  22KB  |  1,106 lines

  1. /* -*- mode: C; mode: fold; -*- */
  2. /* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
  3.  *
  4.  * This file is part of slrn.
  5.  *
  6.  * Slrn is free software; you can redistribute it and/or modify it
  7.  * under the terms of the GNU General Public License as published by the
  8.  * Free Software Foundation; either version 2, or (at your option) any
  9.  * later version.
  10.  * 
  11.  * Slrn is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * for more details.
  15.  * 
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with Slrn; see the file COPYING.  If not, write to the Free
  18.  * Software Foundation, 59 Temple Place - Suite 330, 
  19.  * Boston, MA  02111-1307, USA.
  20.  */
  21.  
  22. #include "config.h"
  23. #include "slrnfeat.h"
  24.  
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <ctype.h>
  28.  
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31.  
  32. #ifdef HAVE_UNISTD_H
  33. # include <unistd.h>
  34. #endif
  35.  
  36. #ifdef HAVE_STDLIB_H
  37. # include <stdlib.h>
  38. #endif
  39.  
  40. #include <slang.h>
  41.  
  42. #define MAX_ARTICLE_LINE_LEN 4096
  43. #include "uudecode.h"
  44. #include "util.h"
  45. #include "ttymsg.h"
  46. #include "slrndir.h"
  47.  
  48. #ifdef STANDALONE
  49. # include <stdarg.h>
  50.  
  51. # if SLRN_HAS_PIPING
  52. #  define SLRN_POPEN uudecode_popen
  53. #  define SLRN_PCLOSE uudecode_pclose
  54. # endif
  55. # define slrn_message_now slrn_tty_message
  56. # define slrn_message slrn_tty_message
  57.  
  58. static FILE *uudecode_popen (char *cmd, char *mode) /*{{{*/
  59. {
  60. # if SLRN_HAS_PIPING
  61.    return popen (cmd, mode);
  62. # else
  63.    slrn_error ("Piping not implemented on this system.");
  64.    return NULL;
  65. # endif
  66. }
  67.  
  68. /*}}}*/
  69.  
  70. static int uudecode_pclose (FILE *fp) /*{{{*/
  71. {
  72. # if SLRN_HAS_PIPING
  73.    return pclose (fp);
  74. # else
  75.    return -1;
  76. # endif
  77. }
  78.  
  79. /*}}}*/
  80.  
  81. #else
  82. # include <slang.h>
  83. # include "jdmacros.h"
  84. # include "slrn.h"
  85. # include "misc.h"
  86. # include "uudecode.h"
  87. # define SLRN_POPEN slrn_popen
  88. # define SLRN_PCLOSE slrn_pclose
  89. char *Slrn_Decode_Directory;
  90. #endif
  91.  
  92. #ifdef VMS
  93. # include "vms.h"
  94. #endif
  95.  
  96. static int uudecode_fclose (FILE *fp, FILE *pipe_fp) /*{{{*/
  97. {
  98.    if ((fp == pipe_fp) || (fp == NULL))
  99.      return 0;
  100.    
  101. #ifdef STANDALONE
  102.    if (0 == fclose (fp)) return 0;
  103.    slrn_error ("Error closing file.  File system full?");
  104.    return -1;
  105. #else
  106.    return slrn_fclose (fp);
  107. #endif
  108. }
  109.  
  110. /*}}}*/
  111.  
  112. static int unpack_as_shell_archive (FILE *fp, char *buf, int size) /*{{{*/
  113. {
  114.    FILE *pp;
  115.    
  116.    size--;
  117.    pp = SLRN_POPEN ("/bin/sh", "w");
  118.    if (pp == NULL)
  119.      {
  120.     slrn_error ("Unable to open /bin/sh\n");
  121.     return -1;
  122.      }
  123.    
  124.    while (fgets (buf, size, fp) != NULL)
  125.      {
  126.     fputs (buf, pp);
  127.     if (!strcmp (buf, "exit 0\n"))
  128.       break;
  129.      }
  130.    
  131.    if (-1 == SLRN_PCLOSE (pp))
  132.      {
  133.     slrn_error ("Error encountered while processing shell archive.\n");
  134.     return -1;
  135.      }
  136.    return 0;
  137. }
  138.  
  139. /*}}}*/
  140.  
  141. static FILE *open_output_file (char *name, char *type, int mode, FILE *use_this) /*{{{*/
  142. {
  143.    FILE *fp;
  144.    
  145.    if (use_this != NULL)
  146.      return use_this;
  147.    
  148.    fp = fopen (name, "wb");
  149.     
  150.    if (fp == NULL)
  151.      {
  152.     slrn_error("Unable to create %s\n", name);
  153.     return NULL;
  154.      }
  155.    
  156.    slrn_message_now ("creating %s (%s)\n", name, type);
  157.    
  158.    if (mode != -1) 
  159.      chmod (name, mode);
  160.    
  161.    return fp;
  162. }
  163.  
  164. /*}}}*/
  165.  
  166. static unsigned char Base64_Table [256];
  167.    
  168. static void initialize_base64 (void) /*{{{*/
  169. {
  170.    int i;
  171.    
  172.    for (i = 0; i < 256; i++) Base64_Table[i] = 0xFF;
  173.    
  174.    for (i = 'A'; i <= 'Z'; i++) Base64_Table[i] = (unsigned char) (i - 'A');
  175.    for (i = 'a'; i <= 'z'; i++) Base64_Table[i] = 26 + (unsigned char) (i - 'a');
  176.    for (i = '0'; i <= '9'; i++) Base64_Table[i] = 52 + (unsigned char) (i - '0');
  177.    Base64_Table['+'] = 62;
  178.    Base64_Table['/'] = 63;
  179. }
  180.  
  181. /*}}}*/
  182.  
  183. /* returns 0 if entire line was decoded, or 1if line appears to be padded, or
  184.  * -1 if line looks bad.
  185.  */
  186. /* Calling routine guarantees at least 4 characters in line and multiple of 4 */
  187. static int base64_decode_line (char *line, FILE *fp) /*{{{*/
  188. {
  189.    unsigned char ch;
  190.    unsigned char ch1;
  191.    unsigned char bytes[3];
  192.    unsigned char *p;
  193.    
  194.    p = (unsigned char *) line;
  195.    /* Perform simple syntax check.  The loop following this one
  196.     * assumes this.
  197.     */
  198.    while ((ch = *p++) != 0)
  199.      {
  200.     if (Base64_Table[ch] == 0xFF)
  201.       return -1;
  202.     
  203.     ch = *p++;
  204.     if (Base64_Table[ch] == 0xFF)
  205.       return -1;
  206.     
  207.     ch = *p++;
  208.     if ((Base64_Table[ch] == 0xFF) && (ch != '='))
  209.       {
  210.          return -1;
  211.       }
  212.  
  213.     ch = *p++;
  214.     if ((Base64_Table[ch] == 0xFF) && (ch != '='))
  215.       {
  216.          return -1;
  217.       }
  218.      }
  219.  
  220.    while ((ch = (unsigned char) *line++) != 0)
  221.      {
  222.     ch1 = Base64_Table[ch];
  223.     bytes[0] = ch1 << 2;
  224.     
  225.     ch = *line++;
  226.     ch1 = Base64_Table[ch];
  227.     
  228.     bytes[0] |= ch1 >> 4;
  229.     bytes[1] = ch1 << 4;
  230.     
  231.     ch = *line++;
  232.     ch1 = Base64_Table[ch];
  233.     if (ch1 == 0xFF)
  234.       {
  235.          fwrite (bytes, 1, 1, fp);
  236.          return 1;
  237.       }
  238.     
  239.     bytes[1] |= ch1 >> 2;
  240.     bytes[2] = ch1 << 6;
  241.     
  242.     ch = *line++;
  243.     ch1 = Base64_Table[ch];
  244.     if (ch1 == 0xFF)
  245.       {
  246.          fwrite (bytes, 1, 2, fp);
  247.          return 1;
  248.       }
  249.     bytes[2] |= ch1;
  250.     fwrite (bytes, 1, 3, fp);
  251.      }
  252.    
  253.    return 0;
  254. }
  255.  
  256. /*}}}*/
  257.  
  258.            
  259.     
  260. static char Base64_Filename[256];
  261. static int Base64_Unknown_Number;
  262.  
  263. /* Returns 1 if padded line which indicates end of encoded file, 0 if
  264.  * decoded something or -1 if nothing.
  265.  */
  266. static int decode_base64 (FILE *fp, FILE *fpout, char *line, unsigned int buflen) /*{{{*/
  267. {
  268.    int decoding = 0;
  269.    unsigned int len;
  270.    int ret;
  271.    
  272.    while (NULL != fgets (line, buflen, fp))
  273.      {
  274.     if (Base64_Table[(unsigned char) *line] == 0xFF)
  275.       {
  276.          if (decoding) return 0;
  277.          else return -1;
  278.       }
  279.     
  280.     len = strlen (line);
  281.     if (len)
  282.       {
  283.          if (line [len - 1] == '\n')
  284.            {
  285.           line[len - 1] = 0;
  286.           len--;
  287.            }
  288.       }
  289.     
  290.     if ((len % 4) != 0)
  291.       {
  292.          if (decoding) return 0;
  293.          else return -1;
  294.       }
  295.     
  296.     ret = base64_decode_line (line, fpout);
  297.     if (ret)
  298.       {
  299.          if ((ret == -1) && decoding) ret = 0;
  300.          return ret;
  301.       }
  302.     
  303.     decoding = 1;
  304.      }
  305.     
  306.    return 0;
  307. }
  308.  
  309. /*}}}*/
  310.  
  311. static char *skip_whitespace (char *p) /*{{{*/
  312. {
  313.    while ((*p == ' ') || (*p == '\t') || (*p == '\n')) p++;
  314.    return p;
  315. }
  316.  
  317. /*}}}*/
  318.  
  319. static char *skip_header_string (char *p, char *name) /*{{{*/
  320. {
  321.    unsigned int len;
  322.    
  323.    p = skip_whitespace (p);
  324.    len = strlen (name);
  325.    
  326.    if (0 != slrn_case_strncmp ((unsigned char *)p, (unsigned char *)name, len))
  327.      return NULL;
  328.    
  329.    return p + len;
  330. }
  331.  
  332. /*}}}*/
  333.  
  334.  
  335. static char *skip_beyond_name_eqs (char *p, char *name) /*{{{*/
  336. {
  337.    int ch;
  338.    unsigned int len;
  339.    
  340.    len = strlen (name);
  341.    
  342.    while (1)
  343.      {
  344.     p = skip_whitespace (p);
  345.     if (*p == 0) return NULL;
  346.     
  347.     if (0 != slrn_case_strncmp ((unsigned char *) p, (unsigned char *) name, len))
  348.       {
  349.          while (((ch = *p) != 0) && (ch != ' ') && (ch != '\t') && (ch != '\n'))
  350.            p++;
  351.          continue;
  352.       }
  353.     
  354.     p = skip_whitespace (p + len);
  355.     if (*p != '=') continue;
  356.  
  357.     p = skip_whitespace (p + 1);
  358.     
  359.     if (*p == 0)
  360.       return NULL;
  361.  
  362.     return p;
  363.      }
  364. }
  365.  
  366. /*}}}*/
  367.  
  368. static int parse_name_eqs_int (char *p, char *name, int *val) /*{{{*/
  369. {
  370.    int ch;
  371.    int ival;
  372.    
  373.    p = skip_beyond_name_eqs (p, name);
  374.    if (p == NULL) return -1;
  375.    
  376.    ival = 0;
  377.    
  378.    while (((ch = *p) != 0) && isdigit(ch))
  379.      {
  380.     ival = ival * 10 + (ch - '0');
  381.     p++;
  382.      }
  383.    
  384.    *val = ival;
  385.    return 0;
  386. }
  387.  
  388. /*}}}*/
  389.  
  390. static int parse_name_eqs_string (char *p, char *name, char *str, unsigned int len) /*{{{*/
  391. {
  392.    char ch;
  393.    char *pmax;
  394.    int quote = 0;
  395.    
  396.    p = skip_beyond_name_eqs (p, name);
  397.    if (p == NULL) return -1;
  398.    
  399.    if (*p == '"') 
  400.      {
  401.     quote = 1;
  402.     p++;
  403.      }
  404.    
  405.    pmax = (p + len) - 1;
  406.    
  407.    while ((p < pmax)
  408.       && ((ch = *p) != '"')
  409.       && (ch != '\n')
  410.       && (ch != 0))
  411.      {
  412.     if ((quote == 0) && ((ch == ' ') || (ch == '\t')))
  413.       break;
  414.     
  415.     *str++ = ch;
  416.     p++;
  417.      }
  418.    *str = 0;
  419.    
  420.    return 0;
  421. }
  422.  
  423. /*}}}*/
  424.  
  425.    
  426.                    
  427. static void parse_content_disposition (char *p) /*{{{*/
  428. {
  429.    (void) parse_name_eqs_string (p, "filename", Base64_Filename, sizeof (Base64_Filename));
  430. }
  431.  
  432. /*}}}*/
  433.  
  434. static int is_encoding_base64 (char *p) /*{{{*/
  435. {
  436.    p = skip_whitespace (p);
  437.    if (slrn_case_strncmp ((unsigned char *)p, (unsigned char *)"base64", 6))
  438.      return 0;
  439.    return 1;
  440. }
  441.  
  442. /*}}}*/
  443.  
  444.  
  445.    
  446. /* Looking for message/pa